#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define NAMESIZE 11
#define RCVPORT 1989
#define IP_SIZE 16
#define BROADCAST "255.255.255.255"

static int __true = 1;

struct msg_st {
    u_int8_t name[NAMESIZE];
    u_int32_t math;
    u_int32_t chinese;
}__attribute__((packed));

void server(const char* bind_address) {
    // socket
    // 0 is default protocol
    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    socklen_t addr_len = (socklen_t) sizeof(struct sockaddr_in);

    if(sd < 0) {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(RCVPORT);
    inet_pton(AF_INET, bind_address, &addr.sin_addr.s_addr);

    // bind
    int r = bind(sd, (void*) &addr, sizeof(struct sockaddr_in));
    if(r < 0) {
        perror("bind");
        exit(0);
    }

    // recvfrom
    while(1) { 
        struct msg_st buf;
        struct sockaddr_in addr;
        ssize_t n = recvfrom(sd, &buf, sizeof(struct msg_st), 0, (void*) &addr, &addr_len);
        char ip[IP_SIZE];
        printf("receive msg from %s:%d\n", inet_ntop(AF_INET, &addr.sin_addr.s_addr, ip, IP_SIZE), ntohs(addr.sin_port));
        printf("name = %s, math = %d, chinese = %d\n", buf.name, ntohs(buf.math), ntohs(buf.chinese));
    }

    // close
    close(sd);
    exit(0);
}


void client(const char* server_addr) {
    // socket
    // 0 is default protocol
    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    socklen_t addr_len = (socklen_t) sizeof(struct sockaddr_in);

    if(strcmp(server_addr, BROADCAST) == 0) {
        if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &__true, sizeof(int)) < 0) {
            perror("setsockopt");
            exit(1);
        }
    }    

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(RCVPORT);
    inet_pton(AF_INET, server_addr, &addr.sin_addr.s_addr);

    if(sd < 0) {
        perror("socket");
        exit(1);
    }

    int math = 0;
    int chinese = 0;
    struct msg_st msg;
    strcpy(msg.name, "strcpy");
    // sendto

    while(1) {  
        msg.math = htons(math);
        msg.chinese = htons(chinese);
        sendto(sd, (void*) &msg, sizeof(struct msg_st), 0, (void*) &addr, addr_len);

        math++;
        chinese++;
        sleep(1);
    }

    exit(0);
}

int main(int argc, char** argv) {
    if (argc < 3 || 
        (
            strcmp(argv[1], "server") != 0 &&
            strcmp(argv[1], "client")
        )
    ) {
        fprintf(stderr, "Usage: %s server or %s client [hostname]\n", argv[0], argv[0]);
        exit(1);
    }

    if(strcmp(argv[1], "server") == 0) {
        server(argv[2]);
    } else {
        client(argv[2]);
    }
}


